Amazon DynamoDB LocalをOSX(Mountain Lion)で実行する
ども、大瀧です。
先ほど、Amazon DynamoDBをローカルで実行する、DynamoDB LocalがAWS Blogで公開されました。早速、手元のMBAで動かしてみました。その軌跡を記録として残しておきます。
Oracle Java SE 7のインストール
OSXにプリインストールされるApple Java 6で動かそうと思ったのですが、以下の@KenTamagawaさんから指摘の通り、JDK 7でないと動作しません。
<blockquote class="twitter-tweet aligncenter" data-conversation="none" data-cards="hidden"><p>JDK7が必要ですー [現在失敗]Amazon DynamoDB LocalをOSX(Mountain Lion)で実行する|クラスメソッド株式会社 開発ブログ 書いた人 > <a href="https://twitter.com/takipone">@takipone</a> <a href="http://t.co/MyU5VpLiI3">http://t.co/MyU5VpLiI3</a></p>— 玉川憲 (@KenTamagawa) <a href="https://twitter.com/KenTamagawa/statuses/378310384047767552">September 13, 2013</a></blockquote>
OSXにOracle Java SE 7がインストールされていなければ、Java SE 7をインストールします。Java SE Downloadsにアクセスし、[Accept License Agreement]のラジオボタンをクリックしつつ、最新のMac OS XのJava SEをダウンロードし、インストールします。
インストールが完了したら、Terminalを開き、java -versionコマンドでJDKのバージョンを確認します。
$ java -version java version "1.7.0_40" Java(TM) SE Runtime Environment (build 1.7.0_40-b43) Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode) $
OKですね。
実行ファイルのダウンロードと展開
DynamoDB Localは、残念ながらソースは公開されていないようで、ビルド済みのファイルが以下のURLで公開されています。
https://s3-us-west-2.amazonaws.com/dynamodb-local/dynamodb_local_2013-09-12.tar.gz
ダウンロードしたら、tarコマンドで任意のディレクトリに展開します。
$ tar zxvf dynamodb_local_2013-09-12.tar.gz x dynamodb_local_2013-09-12/third_party_licenses/httpcore-nio-4.2_NOTICE.txt x dynamodb_local_2013-09-12/third_party_licenses/commons-logging-adapters-1.1.1_LICENSE.txt x dynamodb_local_2013-09-12/third_party_licenses/sqlite4java_LICENSE.txt x dynamodb_local_2013-09-12/third_party_licenses/jackson_LICENSE.txt x dynamodb_local_2013-09-12/third_party_licenses/servlet-api-3.0_LICENSE.txt (略) $
展開したファイルを見ると、.jarファイルの他、各プラットフォームでの実行向けのライブラリファイルも見えますね。
$ cd dynamodb_local_2013-09-12 $ ls DynamoDBLocal.jar libsqlite4java-linux-i386.so sqlite4java-win32-x64.dll LICENSE.txt libsqlite4java-osx-10.4.jnilib sqlite4java-win32-x86.dll README.txt libsqlite4java-osx-ppc.jnilib third_party_licenses/ libsqlite4java-linux-amd64.so libsqlite4java-osx.jnilib
では、実行してみます。
$ java -jar DynamoDBLocal.jar –Djava.library.path=. 2013-09-13 23:57:54.313:INFO:oejs.Server:jetty-8.y.z-SNAPSHOT 2013-09-13 23:57:54.371:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8000 (プロンプトは戻ってこない。Ctrl + Cで終了) ^C $
デフォルトでは、0.0.0.0/0で8000番ポートをListenします。一応、javaコマンドの実行時に--portオプションを付加することで任意のポート番号に変更できるようですが、「Local」と謳うのであれば、ループバックアドレスの127.0.0.1で動かしたいところですよねー。やり方求ム!!
AWS CLIでテーブル作成
では、実際にアクセスしてみましょう。今回は先日正式リリースされたAWS CLIを使ってみます。以下のコマンドラインでは、サンプルとしてAMIの情報を管理するテーブルを作成しています。--endpoint-urlオプションがポイントです。
APIアクセスキーによる認証は行われないのですが、アクセスキーとシークレットキーは環境変数として任意の値で事前に設定しておく必要があります。
$ aws dynamodb create-table --endpoint-url http://localhost:8000 \ --table-name inheritor_ami \ --attribute-definitions AttributeName=ami-id,AttributeType=S \ --key-schema AttributeName=ami-id,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 { "TableDescription": { "AttributeDefinitions": [ { "AttributeName": "ami-id", "AttributeType": "S" } ], "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "WriteCapacityUnits": 1, "ReadCapacityUnits": 1 }, "TableSizeBytes": 0, "TableName": "inheritor_ami", "TableStatus": "ACTIVE", "KeySchema": [ { "KeyType": "HASH", "AttributeName": "ami-id" } ], "ItemCount": 0, "CreationDateTime": 1379085241.731 } } $
テーブルが作成できているか、確認します。
$ aws dynamodb list-tables --endpoint-url http://localhost:8000 { "TableNames": [ "inheritor_ami" ] } $ aws dynamodb describe-table --table-name inheritor_ami --endpoint-url http://localhost:8000 { "Table": { "AttributeDefinitions": [ { "AttributeName": "ami-id", "AttributeType": "S" } ], (略) $
OKですね。
AWS SDK for PHP2でItemをput/getしてみる
まずは、AWS SDK for PHP2でDynamoDB Localに接続するための設定から。AWS SDK for PHP2では、AWS APIにアクセスするための情報を、Aws::factoryメソッドの引数に連想配列で渡します。ここに、base_urlキーでDynamoDB Localのインターフェースおよびポート番号を指定します。
<?php use Aws\Common\Aws; use Aws\Common\Enum\Region; $config = array( 'key' => getenv('AWS_ACCESS_KEY_ID'), 'secret' => getenv('AWS_SECRET_ACCESS_KEY'), 'base_url' => 'http://localhost:8000', 'region' => Region::TOKYO, 'table_prefix' => 'inheritor_' ); $aws = Aws::factory($config); $client = $aws->get('DynamoDb');
あとは、通常のDynamoDBと特に変わりません。今回のサンプルは、モデルクラス(Ami)とDynamoDBのラッパクラス(DynamoDbWrapper)を使っているので、コードの見た目はアレですが、普通にput-itemしています。ソースを見たい方は、GitHubを参照ください。
<?php use Aws\Common\Enum\Region; $ddb = new DynamoDbWrapper($config); $ami = new Ami(); $ami->setAmiId('ami-12345678'); $ami->setRegion(Region::TOKYO); $ami->setParents(array('ami-11111111', 'ami-22222222')); $ami->setChildren(array('ami-33333333', 'ami-44444444')); $ami->setBrothers(array('ami-55555555', 'ami-66666666')); $ddb->persist('ami', $ami); try { $ddb->flush(); } catch (DynamoDbException $e) { print $e; }
あとは、Itemをgetするコードです。こちらもラッパのせいでDynamoDBのAPIを叩いている雰囲気が無くて申し訳ないです...。
try { $item = $ddb->find(array( 'table_name' => 'ami', 'item_key' => 'ami-id', 'item_value' => 'ami-12345678' )); var_dump($item); } catch (DynamoDbException $e) { print $e; }
実行結果としては以下の感じです。
上記コードのvar_dump関数の出力結果
array(5) { ["region"]=> string(14) "ap-northeast-1" ["parents"]=> array(2) { [0]=> string(12) "ami-11111111" [1]=> string(12) "ami-22222222" } ["children"]=> array(2) { [0]=> string(12) "ami-33333333" [1]=> string(12) "ami-44444444" } ["ami-id"]=> string(12) "ami-12345678" ["brothers"]=> array(2) { [0]=> string(12) "ami-55555555" [1]=> string(12) "ami-66666666" } }
ちゃんと取り出せていますね。
DynamoDB Localのデータの実体
DynamoDB Localのデータの実体は、展開したファイルと同じディレクトリに<APIキー名>_<リージョン名>.dbファイルとして作成されます。fileコマンドで調べてみると、SQLiteのデータベースファイルでした。これは接続してみるしか!
$ file XXXXXXXXXXXXXXXXXXXX_ap-northeast-1.db XXXXXXXXXXXXXXXXXXXX_ap-northeast-1.db: SQLite 3.x database $ sqlite3 XXXXXXXXXXXXXXXXXXXX_ap-northeast-1.db SQLite version 3.7.12 2012-04-03 19:43:07 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> .tables dm inheritor_ami sqlite>
テーブルはdmとinheritor_amiの2つがあります。後者はaws dynamodbで作成したテーブルと同名なので、実データが入るテーブルのようです。ということは、dmテーブルは管理用テーブルというところでしょうか。調べてみます。
sqlite> .schema dm CREATE TABLE dm (TableName TEXT, CreationDateTime INTEGER, LastDecreaseDate INTEGER, LastIncreaseDate INTEGER, NumberOfDecreasesToday INTEGER, ReadCapacityUnits INTEGER, WriteCapacityUnits INTEGER, TableInfo BLOB, PRIMARY KEY(TableName)); sqlite> select * from dm; inheritor_ami|1379085241731|0|0|0|1|1|{"Attributes":[{"AttributeName":"ami-id","AttributeType":"S"}],"SQLiteIndex":{"":[{"DynamoDBAttribute":{"AttributeName":"ami-id","AttributeType":"S"},"KeyType":"HASH","SQLiteColumnName":"hashKey","SQLiteDataType":"TEXT"}]},"UniqueIndexes":[{"DynamoDBAttribute":{"AttributeName":"ami-id","AttributeType":"S"},"KeyType":"HASH","SQLiteColumnName":"hashKey","SQLiteDataType":"TEXT"}]} sqlite> .schema inheritor_ami CREATE TABLE "inheritor_ami" (hashKey TEXT DEFAULT NULL, hashValue BLOB NOT NULL, itemSize INTEGER DEFAULT 0, ObjectJSON BLOB NOT NULL, PRIMARY KEY(hashKey)); CREATE INDEX "inheritor_ami*HVI" ON "inheritor_ami" (hashValue); sqlite> select * from inheritor_ami; ami-12345678|�����F��{|133|{"region":{"S":"ap-northeast-1"},"parents":{"SS":["ami-11111111","ami-22222222"]},"children":{"SS":["ami-33333333","ami-44444444"]},"ami-id":{"S":"ami-12345678"},"brothers":{"SS":["ami-55555555","ami-66666666"]}} sqlite>
予想通り、dmテーブルのデータとして、DynamoDBのinheritor_amiテーブルの定義情報が入っていました。inheritor_amiテーブルに、putしたItemが入っていることも確認できました。
まとめ
最後は探究心からちょっと余計なことをしてしまいましたが、触った限りではAmazon DynamoDBと同様に扱えることがわかりました。肝心のThroughputが無制限のためThroughputの制限による例外処理をデバッグできない点は残念ですが、手軽に動作確認できるツールとして非常に有用だと思います。
これまでクラウド破産が怖くてDynamoDBに手が出せなかったデベロッパーのあなた *1、DynamoDB Localを使ってDynamoDBデビューしましょう!
参考URL
- Additional Tools and Libraries For Amazon DynamoDB - Amazon DynamoDB
- Configuration — AWS SDK for PHP 2.4.5 documentation
脚注
- 普通に使う分には、クラウド破産なんてしないですが(汗) ↩